#pragma once

#include <vector>
#include <cstdint>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

class H264FileNaluPars
{
public:
    typedef enum {
        FMT_NONE,
        FMT_H264,
        FMT_H265
    } fmt_type_t;

    /* NALU数据类型 */
    typedef enum {
        NALU_TYPE_SLICE = 1,
        NALU_TYPE_DPA = 2,
        NALU_TYPE_DPB = 3,
        NALU_TYPE_DPC = 4,
        NALU_TYPE_IDR = 5,
        NALU_TYPE_SEI = 6,
        NALU_TYPE_SPS = 7,
        NALU_TYPE_PPS = 8,
        NALU_TYPE_AUD = 9,
        NALU_TYPE_EOSEQ = 10,
        NALU_TYPE_EOSTREAM = 11,
        NALU_TYPE_FILL = 12,
    } H264NaluType;

    /* 重要性IDC */
    typedef enum {
        NALU_PRIORITY_DISPOSABLE = 0,
        NALU_PRIRITY_LOW = 1,
        NALU_PRIORITY_HIGH = 2,
        NALU_PRIORITY_HIGHEST = 3
    } H264NaluPriority;


    typedef struct {
        int statcode_length;
        int forbidden_bit;
        int nal_reference_idc;
        int nal_unit_type;
    
        size_t len;
        size_t max_size;
        unsigned char *buf;
    
        void AppendData(unsigned char *data_buf, size_t data_len) {
            if (max_size - len >= data_len) { // space is not enough
                memcpy(this->buf + this->len, data_buf, data_len);
                this->len += data_len;
            } else {
                this->max_size = this->max_size << 1;
                unsigned char *new_buf = new unsigned char[this->max_size];
                memcpy(new_buf, this->buf, this->len);
                delete[] this->buf;
                this->buf = new_buf;
                this->AppendData(data_buf, data_len);
            }
        }
    } H264Nalu;

    typedef struct {
        int statcode_length;    // 起始码长度
        int forbidden_bit;      // 禁止位
        int nal_reference_idc;  // 帧的重要性
        int nal_unit_type;      // 帧的数据类型

        std::vector<uint8_t> buf;
    } NaluFrame;


    H264FileNaluPars() {}
    ~H264FileNaluPars() {}

    int init(std::string path, fmt_type_t fmt_type);
    int deinit();
    std::vector<uint8_t>& get_nalu_frame();
    
private:
    int get_annexb_nalu();

private:
    const int BUF_MAX{10240};
    FILE *m_h264_fd{nullptr};
    NaluFrame m_nalu_frame{0};

    uint32_t m_nal_num{0};
    uint32_t m_data_offset{0};
    fmt_type_t m_fmt_type;
};